#include <iostream>
#include <cstring>
#include <memory>
#include <vector>
#include <unordered_map>
#include<functional>
#include <sstream>
#include <fstream>
#include "LOG.hpp"
static const std::string header_sep = ": ";
static const std::string sep = "\r\n";
static const std::string wwwroot = "wwwroot";
static const std::string homepage = "index.html";
static const std::string filesuffixsep = ".";
static const std::string space = " ";
static const std::string httpversion = "HTTP/1.0";
static const std::string args_sep = "?";

class HttpRequest;
class HttpResponse;
//返回值HttpResponse   参数HttpRequest
using func_t = std::function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>;
// http内部 要根据目标要访问的资源的文件后缀，区分清楚文件类型
// 通过content-type告诉浏览器，我的response正文的类型
class HttpRequest
{
private:
    // 提取一行
    std::string GetOneLine(std::string &str)
    {
        if (str.empty())
            return str;
        auto pos = str.find(sep);
        if (pos == std::string::npos) // 没找到
        {
            return std::string(); // 返回空串
        }
        std::string line = str.substr(0, pos); // 截取一行
        str.erase(0, pos + sep.size());
        return line.empty() ? sep : line; // 截到空行就return \r\n
    }
    bool ParseHeaderHelper(const std::string &line, std::string *k, std::string *v)
    {
        auto pos = line.find(header_sep);
        if (pos == std::string::npos)
            return false;
        *k = line.substr(0, pos);
        *v = line.substr(pos + header_sep.size());
        return true;
    }

public:
    HttpRequest() : _blank_line(sep), _path(wwwroot)
    {
    }
    void Serialize()
    {
    }
    void DeSerialize(std::string &req)
    {
        _req_line = GetOneLine(req);
        while (true)
        {
            std::string line = GetOneLine(req);
            if (line.empty())
            {
                break;
            }
            else if (line == sep) // 一直截到空行，说明报头已经截取完了
            {
                _req_text = req; // 请求正文填充
                break;
            }
            else // 正常截取一行
            {
                _req_header.emplace_back(line);
            }
        }
        ParseReqLine();
        ParseHeader();
    }
    bool ParseReqLine()
    {
        if (_req_line.empty())
            return false;
        std::stringstream ss(_req_line); // 按空格提取
        ss >> _method >> _url >> _version;

        if (strcasecmp("get",_method.c_str())==0)
        {
            auto pos = _url.find(args_sep); // 在url中找问号
            if (pos != std::string::npos)   // 找到了
            {
                LOG(INFO, "change begin URL: %s\n", _url.c_str());
                _args = _url.substr(pos + args_sep.size()); // 截取参数
                _url.resize(pos);
                LOG(INFO, "change done,URL: %s,_args: %s\n", _url.c_str(), _args.c_str());
            }
        }

        _path += _url;
        LOG(DEBUG, "URL: %s\n", _url.c_str());
        // 判断一下请求的是不是 wwwroot/,是的话往后面+index.html
        if (_path[_path.size() - 1] == '/')
            _path += homepage; //
        auto pos = _path.rfind(filesuffixsep);
        if (pos == std::string::npos)
            _suffix = ".html";
        else
            _suffix = _path.substr(pos);
        LOG(INFO, "client get %s,_suffix: %s \n", _path.c_str(), _suffix.c_str());
        return true;
    }
    bool ParseHeader()
    {
        for (auto &header : _req_header)
        {
            std::string k, v;
            if (ParseHeaderHelper(header, &k, &v))
            {
                _headers.insert(std::make_pair(k, v));
            }
        }
        return true;
    }

    void Print()
    {
        std::cout << "===" << _req_line << std::endl;
        for (auto &header : _req_header)
        {
            std::cout << "***" << header << std::endl;
        }
        std::cout << _blank_line;
        std::cout << _req_text << std::endl;
        std::cout << "method ### " << _method << std::endl;
        std::cout << "url ### " << _url << std::endl;
        std::cout << "httpverion ### " << _version << std::endl;
        for (auto &header : _headers)
        {
            std::cout << "@@@" << header.first << " - " << header.second << std::endl;
        }
    }
    std::string Path()
    {
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }

    bool IsExec()//参数或者正文有一个不为空
    {
        return !_args.empty() || !_req_text.empty();
    }
    std::string Args()
    {
        return _args;
    }
    std::string Text()
    {
        return _req_text;
    }
    std::string Method()
    {
        return _method;
    }
    ~HttpRequest()
    {
    }

private:
    std::string _req_line;                // 请求行
    std::vector<std::string> _req_header; // 请求报头
    std::string _blank_line;              // 空行
    std::string _req_text;                // 请求正文
    // 请求行打散，报头也打散
    std::string _method; // 请求方法
    std::string _url;    // URL
    std::string _path;   // 访问资源的路径
    std::string _suffix;

    std::string _args;    // 参数
    std::string _version; // HTTP版本

    std::unordered_map<std::string, std::string> _headers; // 报头
};

class HttpResponse
{
public:
    HttpResponse() : _version(httpversion), _blank_line(sep)
    {
    }
    // 响应报头
    void AddHander(const std::string &k, const std::string &v)
    {
        LOG(DEBUG, "AddHander: Content-Type%s  -  %s\n", k.c_str(), v.c_str());
        _headers[k] = v;
    }
    // 添加状态行
    void AddStatusLine(int code,const std::string &desc)
    {
        _code = code;
        _desc = "OK";
    }
    // 正文
    void AddText(const std::string &text)
    {
        _resp_text = text;
    }
    std::string Serialize()
    {
        // 状态行填充
        std::string _status_line = _version + space + std::to_string(_code) + space + _desc + sep;
        // 响应报头
        for (auto &header : _headers)
        {
            // resp_header 插入           k           :             v        \r\n
            _resp_header.emplace_back(header.first + header_sep + header.second + sep);
        }

        // 序列化
        std::string respstr = _status_line;
        for (auto &header : _resp_header)
        {
            respstr += header;
        }
        respstr += _blank_line; // 空行
        respstr += _resp_text;  // 正文
        return respstr;
    }
    ~HttpResponse()
    {
    }

private:
    // 构建应答的必要字段
    int _code;                                             // 状态码
    std::string _version;                                  // 版本
    std::string _desc;                                     // 状态码描述
    std::unordered_map<std::string, std::string> _headers; // 到时候k,v添加简单点
    // 结构化的
    std::string _status_line;              // 状态行
    std::vector<std::string> _resp_header; // 响应报头
    std::string _blank_line;               // 空行
    std::string _resp_text;                // 响应正文
};
class Factory
{
public:
    static std::shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }
    static std::shared_ptr<HttpResponse> BuildHttpResponse()
    {
        return std::make_shared<HttpResponse>();
    }
};
class HttpServer
{
public:
    HttpServer()
    {
        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".css", "text/css"));
        _mime_type.insert(std::make_pair(".js", "application/x-javascript"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".jpg", "application/x-jpg"));
        _mime_type.insert(std::make_pair(".gif", "image/gif"));

        // 状态码
        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(201, "Created"));
        _code_to_desc.insert(std::make_pair(204, "No Content"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found or See Other"));
        _code_to_desc.insert(std::make_pair(404, "No Found"));
        _code_to_desc.insert(std::make_pair(500, "Internal Server Error"));
    }

    void AddHandler(const std::string functionname,func_t f)
    {
        std::string key = wwwroot + functionname;//wwwroot/login
        _funcs[key] = f;
    }
    // 要以二进制方式读取
    std::string ReadFileContent(const std::string &path, int *size)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            return std::string();
        }
        in.seekg(0, in.end);       // 定位到最后
        int filesize = in.tellg(); // 文件大小获取
        in.seekg(0, in.beg);       // 定位到最开始
        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize); // 全读完
        *size = filesize;
        in.close();
        return content;
    }
    std::string HandlerHttpRequest(std::string req)
    {
        // request->Print();
        // std::cout << "----------------z-------------------" << std::endl;
        // std::cout << req;
        // std::string response = "HTTP/1.0 200 OK/r/n";
        // response += "Content-Type: text/html; charset=utf-8\r\n";
        // response += "\r\n";
        // response += "<html><body><h1>hello</h1></body></html>";
        // return response;
        // 反序列化
        std::cout << req;
        auto request = Factory::BuildHttpRequest();
        request->DeSerialize(req);
        // int code = 0;

        // 应答
        // auto response = Factory::BuildHttpResponse();
        // std::string newurl = "http://159.75.95.113:8888/image/1.jpg";
        // if (request->Path() == "wwwroot/redir")
        // {
        //     code = 301;
        //     response->AddStatusLine(code, _code_to_desc[code]); // 状态行
        //     response->AddHander("Location", newurl);            // 访问默认跳转到newurl
        // }
        if (request->IsExec())//有参数
        {
            auto response = _funcs[request->Path()](request);
            return response->Serialize();
        }
        else
        {
            auto response = Factory::BuildHttpResponse();
            int code = 200;
            int contentsize = 0;
            std::string text = ReadFileContent(request->Path(), &contentsize);
            if (text.empty()) // text空的状态码设为404
            {
                code = 404;
                response->AddStatusLine(code, _code_to_desc[code]); // 状态行
                std::string text404 = ReadFileContent("wwwroot/404.html", &contentsize);
                response->AddText(text404);
                std::string suffix = request->Suffix();
                response->AddHander("Content_Type", _mime_type[suffix]);
            }
            else
            {
                response->AddStatusLine(code, _code_to_desc[code]);
                response->AddHander("Content-Length", std::to_string(contentsize));
                response->AddText(text);
                std::string suffix = request->Suffix(); // 拿到后缀

                response->AddHander("Content_Type", _mime_type[suffix]);
            }
            // 序列化后返回
            return response->Serialize();
        }

        // 正文
        // response->AddText(text);

    }
    ~HttpServer()
    {
    }

private:
    std::unordered_map<std::string, std::string> _mime_type; // 类型对照表
    std::unordered_map<int, std::string> _code_to_desc;      // 状态码: 状态码描述
    std::unordered_map<std::string,func_t> _funcs;//哈希表建立string和对GET、POST传递参数的处理的函数的映射
};